﻿using System;
using System.Collections.Concurrent;

namespace UtilZ.Dotnet.Ex.Model
{
    /// <summary>
    /// 值域管理器
    /// </summary>
    public class ValueRangeManager
    {
        /// <summary>
        /// key:特定类型;value:特定类型中各个字段或属性对应的值域范围
        /// </summary>
        private readonly ConcurrentDictionary<Type, TypeValueRange> _valueRangeDic = new ConcurrentDictionary<Type, TypeValueRange>();

        /// <summary>
        /// 构造函数
        /// </summary>
        public ValueRangeManager()
        {

        }




        /// <summary>
        /// 添加特定类型值域
        /// </summary>
        /// <typeparam name="T">特定类型</typeparam>
        public void AddTypeValueRange<T>()
        {
            var typeValueRange = new TypeValueRange(typeof(T));
            this.AddTypeValueRange(typeValueRange);
        }

        /// <summary>
        /// 添加特定类型值域
        /// </summary>
        /// <param name="type">特定类型</param>
        public void AddTypeValueRange(Type type)
        {
            var typeValueRange = new TypeValueRange(type);
            this.AddTypeValueRange(typeValueRange);
        }

        /// <summary>
        /// 添加特定类型值域
        /// </summary>
        /// <param name="typeValueRange">特定类型值域对象</param>
        /// <exception cref="ArgumentNullException">特定类型值域对象为null将抛出异常</exception>
        public void AddTypeValueRange(TypeValueRange typeValueRange)
        {
            if (typeValueRange == null)
            {
                throw new ArgumentNullException(nameof(typeValueRange));
            }

            if (!this._valueRangeDic.TryAdd(typeValueRange.Type, typeValueRange))
            {
                throw new ArgumentException($"类型\"{typeValueRange.Type.FullName}\"值域已存在");
            }
        }


        /// <summary>
        /// 判断是否已存在指定类型的字段值域,已存在返回true,不存在返回false
        /// </summary>
        /// <param name="type">要判断的类型</param>
        /// <returns>已存在返回true,不存在返回false</returns>
        /// <exception cref="ArgumentNullException">参数为null</exception>
        public bool Contains(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            return this._valueRangeDic.ContainsKey(type);
        }

        /// <summary>
        /// 移除指定特定类型值域
        /// </summary>
        /// <param name="type">特定类型</param>
        public void RemoveTypeValueRange(Type type)
        {
            TypeValueRange typeValueRange;
            this._valueRangeDic.TryRemove(type, out typeValueRange);
        }

        /// <summary>
        /// 清空所有特定类型值域
        /// </summary>
        public void Clear()
        {
            this._valueRangeDic.Clear();
        }





        /// <summary>
        /// 获取特定类型值域,存在返回值域对象,不存在返回null
        /// </summary>
        /// <typeparam name="T">特定类型</typeparam>
        /// <returns>存在返回定义的值域集合,不存在返回null</returns>
        public TypeValueRange GetTypeValueRange<T>()
        {
            return GetTypeValueRange(typeof(T));
        }

        /// <summary>
        /// 获取特定类型值域,存在返回值域对象,不存在返回null
        /// </summary>
        /// <param name="type">特定类型</param>
        /// <returns>存在返回定义的值域集合,不存在返回null</returns>
        /// <exception cref="ArgumentNullException">特定类型为null将抛出异常</exception>
        public TypeValueRange GetTypeValueRange(Type type)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            TypeValueRange typeParaRange;
            this._valueRangeDic.TryGetValue(type, out typeParaRange);
            return typeParaRange;
        }





        /// <summary>
        /// 添加特定类型下属性或字段值域
        /// </summary>
        /// <typeparam name="T">特定类型</typeparam>
        /// <param name="memberName">属性或字段名称</param>
        /// <param name="fieldValueRange">值域</param>
        /// <exception cref="ArgumentNullException">成员名称为null或空将抛出异常</exception>
        public void AddTypeValueRange<T>(string memberName, IValueRange fieldValueRange)
        {
            this.AddTypeValueRange(typeof(T), memberName, fieldValueRange);
        }

        /// <summary>
        /// 添加特定类型下属性或字段值域
        /// </summary>
        /// <param name="type">特定类型</param>
        /// <param name="memberName">属性或字段名称</param>
        /// <param name="fieldValueRange">值域</param>
        /// <exception cref="ArgumentNullException">特定类型为null或成员名称为null或空将抛出异常</exception>
        public void AddTypeValueRange(Type type, string memberName, IValueRange fieldValueRange)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            if (string.IsNullOrEmpty(memberName))
            {
                throw new ArgumentNullException(nameof(memberName));
            }

            TypeValueRange typeParaRange;
            if (!this._valueRangeDic.TryGetValue(type, out typeParaRange))
            {
                typeParaRange = new TypeValueRange(type);
                this._valueRangeDic.TryAdd(type, typeParaRange);
            }

            typeParaRange.AddValueRange(memberName, fieldValueRange);
        }





        /// <summary>
        /// 尝试获取特定类型下属性或字段的值域,获取成功返回true,获取失败返回false
        /// </summary>
        /// <typeparam name="T">特定类型</typeparam>
        /// <param name="memberName">属性名</param>
        /// <param name="valueRange">值域</param>
        /// <returns>获取成功返回true,获取失败返回false</returns>
        /// <exception cref="ArgumentNullException">成员名称为null或空将抛出异常</exception>
        public bool TryGetTypeValueRange<T>(string memberName, out IValueRange valueRange)
        {
            return this.TryGetTypeValueRange(typeof(T), memberName, out valueRange);
        }

        /// <summary>
        /// 尝试获取特定类型下属性或字段的值域,获取成功返回true,获取失败返回false
        /// </summary>
        /// <param name="type">特定类型</param>
        /// <param name="memberName">属性名</param>
        /// <param name="valueRange">值域</param>
        /// <returns>获取成功返回true,获取失败返回false</returns>
        /// <exception cref="ArgumentNullException">特定类型为null或成员名称为null或空将抛出异常</exception>
        public bool TryGetTypeValueRange(Type type, string memberName, out IValueRange valueRange)
        {
            if (type == null)
            {
                throw new ArgumentNullException(nameof(type));
            }

            if (string.IsNullOrEmpty(memberName))
            {
                throw new ArgumentNullException(nameof(memberName));
            }

            valueRange = null;
            TypeValueRange typeParaRange;
            if (this._valueRangeDic.TryGetValue(type, out typeParaRange))
            {
                return typeParaRange.TryGetValueRange(memberName, out valueRange);
            }
            else
            {
                return false;
            }
        }


    }
}
